

@ccclass
export default class ScrollList extends cc.Component {

    /**总展示区域节点 */
    @property({ type: cc.Node, tooltip: "总展示区域节点" })
    viewArea: cc.Node = null;
    /**要排列显示的预制项 */
    @property({ type: cc.Prefab, tooltip: "要排列显示的预制项" })
    itemPrefab: cc.Prefab = null;

    /**包含可滚动展示内容的小项的父节点 */
    content: cc.Node = null;
    /**content上面的layout组件 */
    contentLayout: cc.Layout = null;

    /**要展示的所有数据 */
    data: [] = null;
    /**已经生成的所有Item */
    allItem: cc.Node[] = [];
    /**可以展示所有Item的最小数量 */
    minShowNum = 0;
    /**记录content的前一个位置，用来判断移动方向 */
    preContentPos: cc.Vec2 = null;

    /**itemPrefab设置数据更新表现的函数名，默认为 "setData" */
    setDataFunctionName = "setData";

    /**要传给Item的额外的数据 */
    extraData: any = null;

    /**初始化所有数据，还可以设置itemPrefab设置数据更新表现的函数名
     * 设置了初始化数据后，界面会显示对应数据的表现界面
     */
    // initData(data: [], optional: { setDataFunctionName?: string, extraData?: any } = {}) {
    //     //保存数据
    //     this.data = data;
    //     this.setDataFunctionName = optional.setDataFunctionName || this.setDataFunctionName;
    //     this.extraData = optional.extraData || this.extraData;
    // }

    /**设置要展示的所有数据，同时更新表现 */
    setData(data: [], optional: { setDataFunctionName?: string, extraData?: any } = {}) {
        this.allItem.forEach((node, index) => {
            node.removeFromParent(true);
        });
        if(data.length == 0) return;
        let setDataFunctionName = optional.setDataFunctionName || this.setDataFunctionName;
        this.extraData = optional.extraData || this.extraData;
        //属性初始化
        if (!this.content) {
            let scrollView = this.getComponent(cc.ScrollView);
            this.content = scrollView.content;
            this.contentLayout = this.content.getComponent(cc.Layout);
        }
        //停止滚动并到最上面
        this.getComponent(cc.ScrollView).stopAutoScroll();
        this.getComponent(cc.ScrollView).scrollToTop(0);
        //算出可以展示所有Item的最小数量
        let viewheight = this.viewArea.height;
        let viewWidth = this.viewArea.width;
        switch (this.contentLayout.type) {
            case cc.Layout.Type.GRID://网格布局
                break;
            case cc.Layout.Type.HORIZONTAL://横向布局
                break;
            case cc.Layout.Type.NONE://没有布局模式
                break;
            case cc.Layout.Type.VERTICAL://竖直布局
                let height = viewheight - this.contentLayout.paddingTop - this.contentLayout.paddingBottom;
                this.minShowNum = Math.ceil(height / (this.itemPrefab.data.height + this.contentLayout.spacingY));
                break;
            default:
                console.error("不支持的布局模式!", this.contentLayout.type);
                break;
        }
        //多2个容错
        this.minShowNum += 2;
        //保存数据
        this.data = data;
        this.setDataFunctionName = setDataFunctionName;
        //算出要生成的数量
        let needNum = data.length > this.minShowNum ? this.minShowNum : data.length;
        //生成或者销毁多余的Item
        let diff = needNum - this.allItem.length;
        if (diff > 0) {//要生成
            let num = Math.abs(diff);
            for (let i = 0; i < num; i++) {
                this.allItem.push(cc.instantiate(this.itemPrefab));
            }
        } else if (diff < 0) {//要销毁
            let num = Math.abs(diff);
            for (let i = 0; i < num; i++) {
                this.allItem.pop().destroy();
            }
        }
        //按位置排序
        if(typeof this.allItem[0]["index"] != "undefined"){
            this.allItem.sort((node1, node2) => {
                return node2.y - node1.y;
            });
        }
        //item放入content
        this.allItem.forEach((node, index) => {
            if (!node.parent) {
                node.parent = this.content;
            }
            node["index"] = index;
            //更新数据
            if (node.getComponent(node.name) && node.getComponent(node.name)[setDataFunctionName]) {
                node.getComponent(node.name)[setDataFunctionName](data[index], this.extraData);
            }
        });
        //布局完后关闭layout
        this.contentLayout.enabled = true;
        this.contentLayout.updateLayout();
        this.contentLayout.enabled = false;
        //改变content
        switch (this.contentLayout.type) {
            case cc.Layout.Type.GRID://网格布局
                break;
            case cc.Layout.Type.HORIZONTAL://横向布局
                break;
            case cc.Layout.Type.NONE://没有布局模式
                break;
            case cc.Layout.Type.VERTICAL://竖直布局
                this.content.height = data.length * this.itemPrefab.data.height + (data.length - 1) * this.contentLayout.spacingY
                    + this.contentLayout.paddingTop + this.contentLayout.paddingBottom;
                break;
            default:
                console.error("不支持的布局模式!", this.contentLayout.type);
                break;
        }
        this.preContentPos = this.content.position;
        console.warn("可以展示所有Item的最小数量", this.minShowNum);
    }

    onLoad() {
        //监听滚动事件
        this.node.on("scrolling", this.updateItem, this);
        this.node.on("scroll-ended", this.updateItem, this);
    }

    /**判断并更新Item表现 */
    updateItem(scrollView?: cc.ScrollView) {
        if(!this.preContentPos || this.allItem.length == 0) return;
        switch (this.contentLayout.type) {
            case cc.Layout.Type.GRID://网格布局
                break;
            case cc.Layout.Type.HORIZONTAL://横向布局
                break;
            case cc.Layout.Type.NONE://没有布局模式
                break;
            case cc.Layout.Type.VERTICAL://竖直布局
                //判断移动方向
                let currentPos = this.content.position;
                if (this.preContentPos.y > currentPos.y) {//向下移动
                    //判断最后一个item是否越界
                    let target = this.allItem[this.allItem.length - 1];
                    let y = this.viewArea.convertToNodeSpaceAR(this.content.convertToWorldSpaceAR(target.position)).y;
                    let bottom = 0;
                    if(this.viewArea.anchorY == 0.5){
                        bottom = -(this.viewArea.height / 2 + target.height / 2 + this.contentLayout.spacingY);
                    }else if(this.viewArea.anchorY == 1){
                        bottom = -(this.viewArea.height + target.height / 2 + this.contentLayout.spacingY);
                    }
                    if (y < bottom) {
                        //判断是否到达顶部
                        if (target["index"] - this.minShowNum >= 0) {
                            target["index"] -= this.minShowNum;
                            //更新位置
                            target.y += this.minShowNum * (this.itemPrefab.data.height + this.contentLayout.spacingY);
                            //更新数组
                            this.allItem.unshift(this.allItem.pop());
                            //更新数据
                            if (target.getComponent(target.name) && target.getComponent(target.name)[this.setDataFunctionName]) {
                                target.getComponent(target.name)[this.setDataFunctionName](this.data[target["index"]], this.extraData);
                            }
                        }
                    }
                } else {//往上移动
                    //判断第一个item是否越界
                    let target = this.allItem[0];
                    let y = this.viewArea.convertToNodeSpaceAR(this.content.convertToWorldSpaceAR(target.position)).y;
                    let top = 0;
                    if(this.viewArea.anchorY == 0.5){
                        top = this.viewArea.height / 2 + target.height / 2 + this.contentLayout.spacingY;
                    }else if(this.viewArea.anchorY == 1){
                        top = target.height / 2 + this.contentLayout.spacingY;
                    }
                    if (y >= top) {
                        //判断是否到达底部
                        if (target["index"] + this.minShowNum < this.data.length) {
                            target["index"] += this.minShowNum;
                            //更新位置
                            target.y -= this.minShowNum * (this.itemPrefab.data.height + this.contentLayout.spacingY);
                            //更新数组
                            this.allItem.push(this.allItem.shift());
                            //更新数据
                            if (target.getComponent(target.name) && target.getComponent(target.name)[this.setDataFunctionName]) {
                                target.getComponent(target.name)[this.setDataFunctionName](this.data[target["index"]], this.extraData);
                            }
                        }
                    }
                }
                this.preContentPos = currentPos;
                break;
            default:
                console.error("不支持的布局模式!", this.contentLayout.type);
                break;
        }
    }

    onDestroy() {
        this.node.off("scrolling", this.updateItem, this);
        this.node.off("scroll-ended", this.updateItem, this);
    }



}